package org.dromara.system.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.MinioService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.minio.utils.file.FileUploadUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.entity.UploadResult;
import org.dromara.common.oss.enumd.AccessPolicyType;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.system.domain.SysMinio;
import org.dromara.system.domain.bo.SysMinioBo;
import org.dromara.system.domain.vo.SysMinioVo;
import org.dromara.system.mapper.SysMinioMapper;
import org.dromara.system.service.ISysMinioService;
import org.jetbrains.annotations.NotNull;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * 文件上传 服务层实现
 */
@RequiredArgsConstructor
@Service
public class SysMinioServiceImpl implements ISysMinioService, MinioService {

    private final SysMinioMapper baseMapper;

    @Override
    public TableDataInfo<SysMinioVo> queryPageList(SysMinioBo bo, PageQuery pageQuery) {
      // 构建查询包装器
        LambdaQueryWrapper<SysMinio> lqw = buildQueryWrapper(bo);
      // 执行分页查询并获取结果
        Page<SysMinioVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
      // 过滤查询结果，只保留需要的字段或进行额外的处理
        List<SysMinioVo> filterResult = StreamUtils.toList(result.getRecords(), this::matchingUrl);
      // 构建并返回表格数据信息对象
        result.setRecords(filterResult);
        return TableDataInfo.build(result);
    }

    @Override
    public List<SysMinioVo> listByIds(Collection<Long> ossIds) {
        List<SysMinioVo> list = new ArrayList<>();
        for (Long id : ossIds) {
          SysMinioVo vo = SpringUtils.getAopProxy(this).getById(id);
            if (ObjectUtil.isNotNull(vo)) {
                try {
                    list.add(this.matchingUrl(vo));
                } catch (Exception ignored) {
                    // 如果oss异常无法连接则将数据直接返回
                    list.add(vo);
                }
            }
        }
        return list;
    }

    @Override
    public String selectUrlByIds(String ossIds) {
        List<String> list = new ArrayList<>();
        for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
            SysMinioVo vo = SpringUtils.getAopProxy(this).getById(id);
            if (ObjectUtil.isNotNull(vo)) {
                try {
                    list.add(this.matchingUrl(vo).getUrl());
                } catch (Exception ignored) {
                    // 如果oss异常无法连接则将数据直接返回
                    list.add(vo.getUrl());
                }
            }
        }
        return String.join(StringUtils.SEPARATOR, list);
    }

    private LambdaQueryWrapper<SysMinio> buildQueryWrapper(SysMinioBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysMinio> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysMinio::getFileName, bo.getFileName());
        lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysMinio::getOriginalName, bo.getOriginalName());
        lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysMinio::getFileSuffix, bo.getFileSuffix());
        lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysMinio::getUrl, bo.getUrl());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
          SysMinio::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.eq(ObjectUtil.isNotNull(bo.getCreateBy()), SysMinio::getCreateBy, bo.getCreateBy());
        lqw.eq(StringUtils.isNotBlank(bo.getService()), SysMinio::getService, bo.getService());
        lqw.orderByDesc(SysMinio::getUpdateTime);
        lqw.orderByAsc(SysMinio::getMinioId);
        return lqw;
    }

    @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId")
    @Override
    public SysMinioVo getById(Long ossId) {
        return baseMapper.selectVoById(ossId);
    }

    @Override
    public void download(Long ossId, HttpServletResponse response) throws IOException {
        SysMinioVo sysMinioVo = SpringUtils.getAopProxy(this).getById(ossId);
        if (ObjectUtil.isNull(sysMinioVo)) {
            throw new ServiceException("文件数据不存在!");
        }
        FileUtils.setAttachmentResponseHeader(response, sysMinioVo.getOriginalName());
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
        OssClient storage = OssFactory.instance(sysMinioVo.getService());
        try(InputStream inputStream = storage.getObjectContent(sysMinioVo.getUrl())) {
            int available = inputStream.available();
            IoUtil.copy(inputStream, response.getOutputStream(), available);
            response.setContentLength(available);
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public SysMinioVo upload(MultipartFile file) {
        String originalfileName = file.getOriginalFilename();
        String suffix = null;
        if (originalfileName != null) {
            suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
        }
        OssClient storage = OssFactory.instance();
        UploadResult uploadResult;
        try {
            uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
        // 保存文件信息
        return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult, null, null);
    }

  @Override
  public SysMinioVo upload(MultipartFile file, String treeValue, String name, String fileName) {
    String originalfileName = file.getOriginalFilename();
    String ContentType = file.getContentType();
    String suffix = null;
    if (Objects.equals(originalfileName, "blob")){
      originalfileName = fileName;
      if (ContentType != null) {
        suffix = "." + StringUtils.substring(ContentType, ContentType.lastIndexOf("/")+1);
      }
    }else{
      if (originalfileName != null) {
        suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
      }
    }
    OssClient storage = OssFactory.instance();
    String configKey = "minio1";
    // 将 UploadResult 的实例化逻辑移到内部类或工具类中
    UploadResult uploadResult = createUploadResult(file, suffix);

    // 保存文件信息
    return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult, treeValue, name);
  }

  private UploadResult createUploadResult(MultipartFile file, String suffix) {
    try {
      String s = FileUploadUtils.uploadMinio(file);
      if (s != null) {
        return new UploadResult(s, FileUtils.getName(s));
      } else {
        throw new ServiceException("文件上传失败，无法获取URL");
      }
    } catch (IOException e) {
      throw new ServiceException(e.getMessage());
    }
  }

  @NotNull
  private SysMinioVo buildResultEntity(String originalFileName, String suffix, String configKey, UploadResult uploadResult, String treeValue, String name) {
    SysMinio minio = new SysMinio();
    minio.setUrl(uploadResult.getUrl());
    minio.setFileSuffix(suffix);
    minio.setFileName(name != null ? name : uploadResult.getFilename());
    minio.setOriginalName(originalFileName);
    minio.setService(configKey);
    if (treeValue != null) {
      minio.setTreeValue(treeValue);
    }
    baseMapper.insert(minio);
    SysMinioVo sysMinioVo = MapstructUtils.convert(minio, SysMinioVo.class);
    return this.matchingUrl(sysMinioVo);
  }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 做一些业务上的校验,判断是否需要校验
        }
        List<SysMinio> list = baseMapper.selectBatchIds(ids);
        for (SysMinio sysMinio : list) {
            OssClient storage = OssFactory.instance(sysMinio.getService());
            storage.delete(sysMinio.getUrl());
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 匹配Url
     *
     *
     */
    private SysMinioVo matchingUrl(SysMinioVo minio) {
        OssClient storage = OssFactory.instance(minio.getService());
        // 仅修改桶类型为 private 的URL，临时URL时长为120s
        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
          minio.setUrl(storage.getPrivateUrl(minio.getFileName(), 120));
        }
        return minio;
    }

    public List<SysMinio> selectOssList(Collection<Long> ids){
        return baseMapper.selectBatchIds(ids);
    }
}
